import mapboxgl, { Map, GeoJSONSource } from 'mapbox-gl';
import { locationIp } from '../config/ip.ts'
import { getAssets } from "@/utils";
interface PointData {
    type: string;
    coordinates: [number, number];
    label?: string;
}

class ClusterLayerManager {
    private map: Map;
    private data: PointData[];
    private imageUrls: { [key: string]: string };
    private sourceId: string = 'points';
    private clusterLayerId: string = 'clusters';
    private clusterCountLayerId: string = 'cluster-count';
    private unclusteredLayerId: string = 'unclustered-point';

    constructor(map: Map, data: PointData[], imageUrls: { [key: string]: string }) {
        this.map = map;
        this.data = data;
        this.imageUrls = imageUrls;
    }

    public async initialize() {
        await this.loadImages();
        this.addSource();
        this.addLayers();
        this.addInteractions();
    }

    private async loadImages() {
        const imageLoadPromises = Object.entries(this.imageUrls).map(([type, url]) => {
            return new Promise<void>((resolve, reject) => {
                this.map.loadImage(url, (error, image) => {
                    if (error) return reject(error);
                    this.map.addImage(type, image);
                    resolve();
                });
            });
        });

        await Promise.all(imageLoadPromises);
    }

    private addSource() {
        const geojsonData = {
            type: 'FeatureCollection',
            features: this.data.map(point => ({
                type: 'Feature',
                geometry: {
                    type: 'Point',
                    coordinates: point.coordinates,
                },
                properties: {
                    type: point.type,
                    label: point.label || '',
                },
            })),
        };
        console.log('添加前', this.sourceId);

        this.map.addSource(this.sourceId, {
            type: 'geojson',
            data: geojsonData,
            // data: getAssets(`data/testData.json`),
            cluster: true, // 启用聚类
            clusterMaxZoom: 14, // 最大聚类缩放级别
            clusterRadius: 50, // 聚类半径
        });
    }

    private addLayers() {
        console.log(`${locationIp}/offlinemap/fonts/{fontstack}/{range}.pbf`)
        this.map.on('load', () => {

        })
        // 添加聚类层
        this.map.addLayer({
            id: this.clusterLayerId,
            type: 'circle',
            source: this.sourceId,
            filter: ['has', 'point_count'], // 只显示聚类点
            paint: {
                'circle-color': [
                    'step',
                    ['get', 'point_count'],
                    '#51bbd6', // 默认颜色
                    100,
                    '#f1f075',
                    750,
                    '#f28cb1',
                ],
                'circle-radius': [
                    'step',
                    ['get', 'point_count'],
                    20/2, // 默认半径
                    100/2,
                    30/2,
                    750/2,
                    40/2,
                ],
            },
        });
        console.log(this.sourceId, this.clusterCountLayerId);

        // 添加聚类数量标签层
        this.map.addLayer({
            id: this.clusterCountLayerId,
            type: 'symbol',
            source: this.sourceId,
            filter: ['has', 'point_count'],
            layout: {
                'text-field':  ['get', 'point_count_abbreviated'],
                'text-font': ["Open Sans Bold"],
                'text-size': 12,
                
            },
        });

        // 添加未聚类点层
        this.map.addLayer({
            id: this.unclusteredLayerId,
            type: 'symbol',
            source: this.sourceId,
            // filter: ['!', ['has', 'point_count']], // 只显示未聚类点
            layout: {
                'icon-image': ['get', 'type'], // 根据类型显示图标
                'icon-size': 1,
                'text-field': ['get', 'label'], // 显示标签
                'text-font': ["Microsoft YaHei"],
                'text-offset': [0, 1.5],
                'text-anchor': 'top',
            },
        });
    }

    private addInteractions() {
        // 点击聚类点时放大
        this.map.on('click', this.clusterLayerId, (e) => {
            const features = this.map.queryRenderedFeatures(e.point, {
                layers: [this.clusterLayerId],
            });
            const clusterId = features[0].properties?.cluster_id;
            const source = this.map.getSource(this.sourceId) as GeoJSONSource;

            source.getClusterExpansionZoom(clusterId, (err, zoom) => {
                if (err) return;

                this.map.easeTo({
                    center: (features[0].geometry as any).coordinates,
                    zoom: zoom,
                });
            });
        });

        // 鼠标悬停时显示指针
        this.map.on('mouseenter', this.clusterLayerId, () => {
            this.map.getCanvas().style.cursor = 'pointer';
        });
        this.map.on('mouseleave', this.clusterLayerId, () => {
            this.map.getCanvas().style.cursor = '';
        });
    }

    // 显示或隐藏特定类型的点
    public toggleTypeVisibility(type: string, visible: boolean) {
        const filter = visible
            ? ['==', ['get', 'type'], type] // 显示特定类型
            : ['!=', ['get', 'type'], type]; // 隐藏特定类型

        this.map.setFilter(this.unclusteredLayerId, ['all', ['!', ['has', 'point_count']], filter]);
    }

    // 删除特定类型的点
    public removeType(type: string) {
        const source = this.map.getSource(this.sourceId) as GeoJSONSource;
        const currentData = (source as any)._data; // 获取当前数据

        if (currentData && currentData.features) {
            const newFeatures = currentData.features.filter(
                (feature: any) => feature.properties.type !== type
            );

            source.setData({
                type: 'FeatureCollection',
                features: newFeatures,
            });
        }
    }

    // 更新数据源
    public updateData(newData: PointData[]) {
        const source = this.map.getSource(this.sourceId) as GeoJSONSource;

        const geojsonData = {
            type: 'FeatureCollection',
            features: newData.map(point => ({
                type: 'Feature',
                geometry: {
                    type: 'Point',
                    coordinates: point.coordinates,
                },
                properties: {
                    type: point.type,
                    label: point.label || '',
                },
            })),
        };

        source.setData(geojsonData);
    }
}

export { ClusterLayerManager };